package com.baofu.paycore.biz.paycore.handler.impl;

import com.baofu.paycore.biz.engine.command.Command;
import com.baofu.paycore.biz.engine.executor.CommandExecutor;
import com.baofu.paycore.biz.engine.generator.CommandGenerator;
import com.baofu.paycore.biz.engine.result.CommandResult;
import com.baofu.paycore.biz.model.BackPayBO;
import com.baofu.paycore.biz.paycore.converter.BO2BOConverter;
import com.baofu.paycore.biz.paycore.handler.BaseHandler;
import com.baofu.paycore.common.exception.PayCoreBizException;
import com.baofu.paycore.manager.model.ResponseBO;
import com.baofu.paycore.service.facade.enums.PayCoreErrorCode;
import com.baofu.paycore.manager.model.preAuth.PreAuthBO;
import com.baofu.paycore.manager.model.preAuth.SubPreAuthBO;
import com.baofu.paycore.manager.storer.PreAuthRepository;
import com.baofu.paycore.service.facade.enums.PayStatusEnums;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.List;
import java.util.Map;
import java.util.Objects;

/**
 * 预授权撤销处理
 *
 * <p>
 *  1.预授权撤销订单处理
 * </p>
 * User: xin deng  Date: 16/8/31 ProjectName: paycore Version: 1.0
 */
@Slf4j
@Service
public class PreAuthCancelHandler extends BaseHandler<PreAuthBO,SubPreAuthBO> {

    @Autowired
    private PreAuthRepository preAuthRepository;

    /**
     * 支付指令生成
     */
    @Resource(name = "preAuthCancelCommandGenerator")
    protected CommandGenerator<PreAuthBO> preAuthCancelCommandGenerator;

    /**
     * 指令执行
     */
    @Resource
    protected CommandExecutor commandExecutor;

    /**
     * 预授权撤销处理
     *
     * @param preAuthBO 订单对象
     * @return BackPayBo
     */
    @Override
    public BackPayBO process(PreAuthBO preAuthBO) {
        log.info("预授权撤销开始处理：{}", preAuthBO);
        doExecute(preAuthBO);
        log.info("预授权撤销完成结果：{}",preAuthBO);
        return BO2BOConverter.preAuthBO2BackPayBO(preAuthBO);
    }

    /**
     * 激活领域对象
     *
     * @param orderId 订单ID
     * @return 订单对象
     */
    @Override
    public PreAuthBO activeOrder(String orderId) {
        PreAuthBO preAuthBO = preAuthRepository.load(orderId);
        if(preAuthBO == null){
            log.error("找不到预授权订单:{}",orderId);
            throw new PayCoreBizException(PayCoreErrorCode.ORDER_IS_NOT_EXISTED);
        }
        return preAuthBO;
    }

    /**
     * 查询订单信息
     *
     * @param payNo 支付单号
     * @return 订单对象
     */
    @Override
    public PreAuthBO queryOrderByPayNo(String payNo) {
        PreAuthBO preAuthBO = preAuthRepository.load(payNo);
        if(preAuthBO == null){
            log.error("找不到预授权取消订单:{}",payNo);
            throw new PayCoreBizException(PayCoreErrorCode.ORDER_IS_NOT_EXISTED);
        }
        return preAuthBO;
    }

    /**
     * 前置检查
     *
     * @param order 订单
     */
    @Override
    protected void checkBeforeProcess(PreAuthBO order) {
        order.checkStatus();
    }

    /**
     * 生成指令
     *
     * @param order 单据
     */
    @Override
    protected void processOrders(PreAuthBO order) {
        List<Command> commands = preAuthCancelCommandGenerator.generatorCommands(order);

        log.info("预授权撤销指令, commands:{}", commands);

        Map<String, CommandResult> cmdResults = commandExecutor.executeCommand(commands);

        log.info("预授权撤销指令执行结果, cmdResults:{}",cmdResults);
        order.setRealFlag(true);
        processAfter(order, cmdResults);
    }

    /**
     * 持久化对象
     *
     * @param order 单据
     */
    @Override
    protected void reStore(PreAuthBO order) {
        if (PayStatusEnums.SUCCESS.getCode().equals(order.getStatus())){
            preAuthRepository.updatePreAuthCancel(order);
            return;
        }
        preAuthRepository.update(order);
    }

    /**
     * 指令完成后处理
     *
     * @param order     领域模型
     * @param cmdResult 指令处理结果
     */
    @Override
    protected void processAfter(PreAuthBO order, Map<String, CommandResult> cmdResult) {
        //遍历所有资金单返回结果
        cmdResult.entrySet().forEach(each->
            setFundDetailStatus(each, order)
        );
        finalCheck(order, cmdResult);
        log.info("预授权撤销主单状态status:{}", order.getStatus());
    }

    /**
     * 设置资金单状态
     *
     * @param entry         处理结果
     * @param preAuthBO     预授权单
     */
    private void setFundDetailStatus(Map.Entry<String, CommandResult> entry,PreAuthBO preAuthBO) {
        SubPreAuthBO subPreAuthBO = preAuthBO.getSubPreAuthBO().get(0);
        CommandResult commandResult = entry.getValue();
        subPreAuthBO.setTransReceiptNo(commandResult.getResponseNo());
        subPreAuthBO.setTransDate(commandResult.getResponseDate());
        subPreAuthBO.setErrorCode(commandResult.getResultCode());
        subPreAuthBO.setErrorReason(commandResult.getResultMsg());

        if(!commandResult.isRealRtnFlag()){
            subPreAuthBO.setErrorCode(null);
            subPreAuthBO.setStatus(PayStatusEnums.INIT.getCode());
            return;
        }
        subPreAuthBO.setStatus(commandResult.getStatus());
    }

    /**
     * 支付状态校验
     *
     * @param order         订单
     * @param cmdResult     处理结果集
     */
    private void finalCheck(PreAuthBO order, Map<String, CommandResult> cmdResult){
        //出现未知的指令时将不会调用账务接口，更新单据状态为失败
        if (cmdResult.size() == 0 ) {
            //资金单中，只要有一单支付失败，主单为失败
            order.getSubPreAuthBO().get(0).setStatus(PayStatusEnums.FAIL.getCode());
            order.setStatus(PayStatusEnums.FAIL.getCode());
            return;
        }
        cmdResult.values().forEach(commandResult->{

            if(!commandResult.isRealRtnFlag() ||
                    Objects.equals(PayStatusEnums.INIT.getCode(), commandResult.getStatus())){
                order.setErrorCode(commandResult.getResultCode());
                order.setErrorMsg(commandResult.getResultMsg());
                order.setStatus(PayStatusEnums.INIT.getCode());
                return;
            }

            if(PayStatusEnums.FAIL.getCode().equals(commandResult.getStatus())){
                order.setErrorCode(commandResult.getResultCode());
                order.setStatus(PayStatusEnums.FAIL.getCode());
                order.setErrorMsg(commandResult.getResultMsg());
                return;
            }

            if (PayStatusEnums.SUCCESS.getCode().equals(commandResult.getStatus())){
                order.setStatus(PayStatusEnums.SUCCESS.getCode());
            }
        });
    }
    /**
     * 需重试接口 对内部资金单的重试（订单状态推进）
     *
     * @param preAuthBO  预授权取消订单对象
     * @return ResponseBO
     * @throws RuntimeException 出现异常时表示重试没有成功（子类方法实现中不可捕获异常）
     */
    public ResponseBO dalInnerFundProc(PreAuthBO preAuthBO) throws RuntimeException {
        ResponseBO responseBO = null;
        List <SubPreAuthBO> subPreAuthBOS=preAuthBO.getSubPreAuthBO();
        //获取冻结单
        SubPreAuthBO subPreAuthBO=subPreAuthBOS.get(0);
        if (PayStatusEnums.FAIL.getCode().equals(subPreAuthBO.getStatus())||PayStatusEnums.SUCCESS.getCode().equals(subPreAuthBO.getStatus())){
            log.error("重试接口 单号:{}, 冻结单状态:{}", subPreAuthBO.getPayNo(), subPreAuthBO.getStatus());
            return new ResponseBO(subPreAuthBO.getStatus(), subPreAuthBO.getErrorCode(),
                    subPreAuthBO.getErrorReason(), subPreAuthBO.getPayNo(), preAuthBO.isRealFlag());
        }else{
            log.info("预授权取消payNo:{},状态:{},未成功,走整个流程", subPreAuthBO.getPayNo(), subPreAuthBO.getStatus());
            this.processOrders(preAuthBO);
            preAuthRepository.update(preAuthBO);
            return new ResponseBO(preAuthBO.getStatus(), preAuthBO.getErrorCode(),
                    preAuthBO.getErrorMsg(), preAuthBO.getPayNo(), preAuthBO.isRealFlag());
        }
    }
}
